#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
COM线程管理器
负责管理UI自动化操作的线程安全性，防止多个操作同时访问COM对象
"""

# 修复COM线程冲突：设置COM为多线程模式
import sys
sys.coinit_flags = 0  # COINIT_MULTITHREADED，允许多线程访问COM对象

import threading
import time
import logging
import queue
from typing import Callable, Any, Optional, Dict
from enum import Enum
from concurrent.futures import ThreadPoolExecutor, Future
from datetime import datetime


class TaskStatus(Enum):
    """任务状态枚举"""
    PENDING = "pending"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"
    CANCELLED = "cancelled"


class TaskPriority(Enum):
    """任务优先级枚举"""
    LOW = 0
    NORMAL = 1
    HIGH = 2
    CRITICAL = 3


class COMTask:
    """COM任务包装器"""

    def __init__(self, task_id: str, func: Callable, args: tuple = (), kwargs: dict = None,
                 max_retries: int = 1, priority: TaskPriority = TaskPriority.NORMAL):
        self.task_id = task_id
        self.func = func
        self.args = args
        self.kwargs = kwargs or {}
        self.max_retries = max_retries
        self.priority = priority
        self.current_retry = 0
        self.status = TaskStatus.PENDING
        self.result = None
        self.error = None
        self.retry_errors = []
        self.created_time = datetime.now()
        self.start_time = None
        self.end_time = None

        # 添加超时控制
        self.timeout = kwargs.pop('task_timeout', None) if kwargs else None

    def execute(self):
        """执行任务（支持重试）"""
        try:
            self.status = TaskStatus.RUNNING
            self.start_time = datetime.now()

            for attempt in range(self.max_retries + 1):
                self.current_retry = attempt
                try:
                    self.result = self.func(*self.args, **self.kwargs)
                    self.status = TaskStatus.COMPLETED
                    return self.result
                except Exception as e:
                    error_msg = str(e)
                    self.retry_errors.append(f"尝试 {attempt + 1}: {error_msg}")

                    if attempt < self.max_retries:
                        # 还有重试机会，等待一段时间后重试
                        time.sleep(2 ** attempt)  # 指数退避
                        continue
                    else:
                        # 最后一次尝试也失败了
                        self.error = f"任务失败，已重试 {self.max_retries} 次。错误: {error_msg}"
                        self.status = TaskStatus.FAILED
                        raise Exception(self.error)
        finally:
            self.end_time = datetime.now()


class COMThreadManager:
    """COM线程管理器

    确保所有UI自动化操作在单一线程中执行，避免COM对象冲突
    """

    def __init__(self, max_workers: int = 1):
        self.max_workers = max_workers
        self.logger = logging.getLogger(__name__)

        # 任务队列和执行器
        self.task_queue = queue.Queue()
        self.executor = ThreadPoolExecutor(max_workers=max_workers, thread_name_prefix="COM-Worker")

        # 任务管理
        self.tasks: Dict[str, COMTask] = {}
        self.futures: Dict[str, Future] = {}

        # 线程锁和状态
        self.lock = threading.RLock()
        self.is_busy = False
        self.current_task_id = None

        # 启动清理线程
        self.cleanup_thread = threading.Thread(target=self._cleanup_completed_tasks, daemon=True)
        self.cleanup_thread.start()

        self.logger.info("COM线程管理器初始化完成")

    def submit_task(self, task_id: str, func: Callable, args: tuple = (), kwargs: dict = None,
                   wait_for_result: bool = False, timeout: Optional[float] = None,
                   max_retries: int = 1, priority: TaskPriority = TaskPriority.NORMAL) -> Any:
        """提交COM任务

        Args:
            task_id: 任务ID
            func: 要执行的函数
            args: 函数参数
            kwargs: 函数关键字参数
            wait_for_result: 是否等待结果
            timeout: 超时时间（秒）

        Returns:
            如果wait_for_result=True，返回执行结果；否则返回任务ID
        """
        with self.lock:
            # 检查任务ID是否已存在
            if task_id in self.tasks:
                existing_task = self.tasks[task_id]
                if existing_task.status in [TaskStatus.PENDING, TaskStatus.RUNNING]:
                    raise ValueError(f"任务 {task_id} 已在执行中")

            # 创建新任务
            task = COMTask(task_id, func, args, kwargs, max_retries, priority)
            self.tasks[task_id] = task

            # 提交到线程池
            future = self.executor.submit(self._execute_task_safely, task)
            self.futures[task_id] = future

            self.logger.info(f"提交COM任务: {task_id}")

            if wait_for_result:
                try:
                    result = future.result(timeout=timeout)
                    return result
                except Exception as e:
                    self.logger.error(f"任务 {task_id} 执行失败: {e}")
                    raise
            else:
                return task_id

    def _execute_task_safely(self, task: COMTask) -> Any:
        """安全执行COM任务（增强版，支持超时和更好的锁管理）"""
        import signal
        import threading

        # 使用更细粒度的锁管理
        lock_acquired = False
        lock_timeout = 30  # 30秒锁超时

        def timeout_handler(signum, frame):
            raise TimeoutError(f"任务 {task.task_id} 执行超时")

        old_busy = False
        old_task_id = None

        try:
            # 尝试获取锁，设置超时
            lock_acquired = self.lock.acquire(timeout=lock_timeout)
            if not lock_acquired:
                raise TimeoutError(f"任务 {task.task_id} 获取锁超时")

            # 检查系统是否过度繁忙
            if self.is_busy and task.priority.value < TaskPriority.HIGH.value:
                # 非高优先级任务在系统繁忙时等待
                self.lock.release()
                lock_acquired = False
                time.sleep(1)
                # 重新尝试获取锁
                lock_acquired = self.lock.acquire(timeout=lock_timeout)
                if not lock_acquired:
                    raise TimeoutError(f"任务 {task.task_id} 重新获取锁超时")

            # 设置忙状态
            old_busy = self.is_busy
            old_task_id = self.current_task_id
            self.is_busy = True
            self.current_task_id = task.task_id

            # 释放锁，开始执行任务
            self.lock.release()
            lock_acquired = False

            self.logger.info(f"开始执行COM任务: {task.task_id} (优先级: {task.priority.name})")

            # COM初始化（使用线程局部存储避免冲突）
            self._ensure_com_initialized_safe()

            # 设置任务超时
            if task.timeout:
                if hasattr(signal, 'SIGALRM'):  # Unix系统
                    signal.signal(signal.SIGALRM, timeout_handler)
                    signal.alarm(int(task.timeout))

            try:
                # 执行任务
                result = task.execute()
                self.logger.info(f"COM任务执行完成: {task.task_id}")
                return result
            finally:
                # 清除超时
                if task.timeout and hasattr(signal, 'SIGALRM'):
                    signal.alarm(0)

        except Exception as e:
            self.logger.error(f"COM任务执行失败: {task.task_id}, 错误: {e}")
            # 如果是超时或锁问题，标记为可恢复的错误
            if isinstance(e, TimeoutError):
                task.status = TaskStatus.FAILED
                task.error = f"任务超时: {str(e)}"
            raise
        finally:
            # 确保释放锁
            if lock_acquired:
                self.lock.release()

            # 恢复状态（重新获取锁）
            try:
                with self.lock:
                    self.is_busy = old_busy
                    self.current_task_id = old_task_id
            except:
                # 如果锁出现问题，强制重置状态
                self.is_busy = False
                self.current_task_id = None
                self.logger.warning(f"强制重置COM管理器状态 (任务: {task.task_id})")

            # COM清理（在锁外执行）
            self._cleanup_com_safe()

    def _ensure_com_initialized_safe(self):
        """安全的COM初始化（使用线程局部存储）"""
        import threading
        thread_local = threading.local()

        try:
            # 检查当前线程是否已经初始化COM
            if hasattr(thread_local, 'com_initialized') and thread_local.com_initialized:
                return

            import pythoncom
            # 检查是否已经初始化
            try:
                # 尝试获取当前的初始化状态
                pythoncom.CoGetCurrentProcess()
                self.logger.debug("COM已经初始化（线程局部）")
                thread_local.com_initialized = True
                return
            except:
                pass

            # 使用多线程套间模式初始化COM，解决GUI与API服务的冲突
            pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)
            thread_local.com_initialized = True
            self.logger.debug("COM初始化成功（多线程套间模式，线程局部）")

        except ImportError:
            # pythoncom不可用，跳过
            self.logger.debug("pythoncom不可用，跳过COM初始化")
        except Exception as e:
            self.logger.warning(f"COM初始化警告: {e}")
            # 作为后备，尝试标准初始化
            try:
                import pythoncom
                pythoncom.CoInitialize()
                thread_local.com_initialized = True
                self.logger.info("COM后备初始化成功（多线程模式，线程局部）")
            except:
                self.logger.error("COM初始化完全失败（线程局部）")

    def _cleanup_com_safe(self):
        """安全的COM清理（使用线程局部存储）"""
        import threading
        thread_local = threading.local()

        try:
            if not hasattr(thread_local, 'com_initialized') or not thread_local.com_initialized:
                return

            import pythoncom
            # 清理当前线程的COM
            pythoncom.CoUninitialize()
            thread_local.com_initialized = False
            self.logger.debug("COM清理成功（线程局部）")

        except ImportError:
            # pythoncom不可用，跳过
            self.logger.debug("pythoncom不可用，跳过COM清理")
        except Exception as e:
            self.logger.warning(f"COM清理警告: {e}")
            # 强制清理
            try:
                import pythoncom
                pythoncom.CoUninitialize()
                thread_local.com_initialized = False
            except:
                pass

    def _ensure_com_initialized(self):
        """确保COM已正确初始化（防护式初始化）"""
        try:
            import pythoncom
            # 检查是否已经初始化
            try:
                # 尝试获取当前的初始化状态
                pythoncom.CoGetCurrentProcess()
                self.logger.debug("COM已经初始化")
                return
            except:
                pass

            # 使用多线程套间模式初始化COM，解决GUI与API服务的冲突
            pythoncom.CoInitializeEx(pythoncom.COINIT_MULTITHREADED)
            self.logger.debug("COM初始化成功（多线程套间模式）")
        except ImportError:
            # pythoncom不可用，跳过
            self.logger.debug("pythoncom不可用，跳过COM初始化")
        except Exception as e:
            self.logger.warning(f"COM初始化警告: {e}")
            # 作为后备，尝试标准初始化
            try:
                import pythoncom
                pythoncom.CoInitialize()
                self.logger.info("COM后备初始化成功（多线程模式）")
            except:
                self.logger.error("COM初始化完全失败")

    def _cleanup_com(self):
        """清理COM资源"""
        try:
            import pythoncom
            # 清理当前线程的COM
            pythoncom.CoUninitialize()
            self.logger.debug("COM清理成功")
        except ImportError:
            # pythoncom不可用，跳过
            self.logger.debug("pythoncom不可用，跳过COM清理")
        except Exception as e:
            self.logger.warning(f"COM清理警告: {e}")
            # 强制清理
            try:
                import pythoncom
                pythoncom.CoUninitialize()
            except:
                pass

    def get_task_status(self, task_id: str) -> Dict[str, Any]:
        """获取任务状态"""
        with self.lock:
            if task_id not in self.tasks:
                return {"error": "任务不存在"}

            task = self.tasks[task_id]
            status_info = {
                "task_id": task_id,
                "status": task.status.value,
                "created_time": task.created_time.isoformat(),
                "start_time": task.start_time.isoformat() if task.start_time else None,
                "end_time": task.end_time.isoformat() if task.end_time else None,
                "args": task.args,
                "kwargs": task.kwargs,
            }

            if task.status == TaskStatus.COMPLETED:
                status_info["result"] = task.result
            elif task.status == TaskStatus.FAILED:
                status_info["error"] = task.error

            return status_info

    def cancel_task(self, task_id: str) -> bool:
        """取消任务"""
        with self.lock:
            if task_id not in self.futures:
                return False

            future = self.futures[task_id]
            if future.cancel():
                if task_id in self.tasks:
                    self.tasks[task_id].status = TaskStatus.CANCELLED
                self.logger.info(f"任务已取消: {task_id}")
                return True
            return False

    def is_task_running(self, task_id: str) -> bool:
        """检查任务是否正在运行"""
        with self.lock:
            if task_id not in self.tasks:
                return False
            return self.tasks[task_id].status == TaskStatus.RUNNING

    def is_system_busy(self) -> bool:
        """检查系统是否忙碌"""
        with self.lock:
            return self.is_busy

    def get_current_task(self) -> Optional[str]:
        """获取当前执行的任务ID"""
        with self.lock:
            return self.current_task_id

    def list_tasks(self, include_completed: bool = False) -> Dict[str, Dict[str, Any]]:
        """列出所有任务"""
        with self.lock:
            result = {}
            for task_id, task in self.tasks.items():
                if not include_completed and task.status in [TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED]:
                    continue
                result[task_id] = self.get_task_status(task_id)
            return result

    def _cleanup_completed_tasks(self):
        """清理已完成的任务（后台线程）"""
        while True:
            try:
                time.sleep(60)  # 每60秒清理一次

                with self.lock:
                    # 获取需要清理的任务
                    to_remove = []
                    current_time = datetime.now()

                    for task_id, task in self.tasks.items():
                        # 清理1小时前完成的任务
                        if (task.status in [TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.CANCELLED] and
                            task.end_time and
                            (current_time - task.end_time).total_seconds() > 3600):
                            to_remove.append(task_id)

                    # 删除任务
                    for task_id in to_remove:
                        del self.tasks[task_id]
                        if task_id in self.futures:
                            del self.futures[task_id]
                        self.logger.debug(f"清理已完成任务: {task_id}")

            except Exception as e:
                self.logger.error(f"清理任务异常: {e}")

    def shutdown(self, wait: bool = True):
        """关闭线程管理器"""
        self.logger.info("正在关闭COM线程管理器...")
        self.executor.shutdown(wait=wait)
        self.logger.info("COM线程管理器已关闭")


# 全局COM线程管理器实例
_com_thread_manager = None
_manager_lock = threading.Lock()


def get_com_thread_manager() -> COMThreadManager:
    """获取全局COM线程管理器实例"""
    global _com_thread_manager

    if _com_thread_manager is None:
        with _manager_lock:
            if _com_thread_manager is None:
                _com_thread_manager = COMThreadManager()

    return _com_thread_manager


def execute_com_task(task_id: str, func: Callable, args: tuple = (), kwargs: dict = None,
                    wait_for_result: bool = False, timeout: Optional[float] = None,
                    priority: TaskPriority = TaskPriority.NORMAL) -> Any:
    """执行COM任务的便捷函数"""
    manager = get_com_thread_manager()
    return manager.submit_task(task_id, func, args, kwargs, wait_for_result, timeout, priority=priority)


if __name__ == "__main__":
    # 测试代码
    import logging
    logging.basicConfig(level=logging.INFO)

    def test_func(x, y):
        time.sleep(2)
        return x + y

    manager = get_com_thread_manager()

    # 测试异步执行
    task_id = manager.submit_task("test1", test_func, (1, 2))
    print(f"提交任务: {task_id}")

    # 等待结果
    while True:
        status = manager.get_task_status(task_id)
        print(f"任务状态: {status}")
        if status["status"] in ["completed", "failed"]:
            break
        time.sleep(0.5)

    # 测试同步执行
    result = manager.submit_task("test2", test_func, (3, 4), wait_for_result=True)
    print(f"同步结果: {result}")

    manager.shutdown()